return 0;
}
-int xb_wait_for_data_to_read(void)
+int xb_data_to_read(void)
{
struct xenstore_domain_interface *intf = xen_store_interface;
- return wait_event_interruptible(
- xb_waitq,
- intf->rsp_cons != intf->rsp_prod);
+ return (intf->rsp_cons != intf->rsp_prod);
+}
+
+int xb_wait_for_data_to_read(void)
+{
+ return wait_event_interruptible(xb_waitq, xb_data_to_read());
}
int xb_read(void *data, unsigned len)
/* Set up interrupt handler off store event channel. */
int xb_init_comms(void)
{
+ struct xenstore_domain_interface *intf = xen_store_interface;
int err;
+ if (intf->req_prod != intf->req_cons)
+ printk(KERN_ERR "XENBUS request ring is not quiescent "
+ "(%08x:%08x)!\n", intf->req_cons, intf->req_prod);
+
+ if (intf->rsp_prod != intf->rsp_cons) {
+ printk(KERN_WARNING "XENBUS response ring is not quiescent "
+ "(%08x:%08x): fixing up\n",
+ intf->rsp_cons, intf->rsp_prod);
+ intf->rsp_cons = intf->rsp_prod;
+ }
+
if (xenbus_irq)
unbind_from_irqhandler(xenbus_irq, &xb_waitq);
/* Low level routines. */
int xb_write(const void *data, unsigned len);
int xb_read(void *data, unsigned len);
+int xb_data_to_read(void);
int xb_wait_for_data_to_read(void);
int xs_input_avail(void);
extern struct xenstore_domain_interface *xen_store_interface;
/* One request at a time. */
struct mutex request_mutex;
+ /* Protect xenbus reader thread against save/restore. */
+ struct mutex response_mutex;
+
/* Protect transactions against save/restore. */
struct rw_semaphore suspend_mutex;
};
{
down_write(&xs_state.suspend_mutex);
mutex_lock(&xs_state.request_mutex);
+ mutex_lock(&xs_state.response_mutex);
}
void xs_resume(void)
struct xenbus_watch *watch;
char token[sizeof(watch) * 2 + 1];
+ mutex_unlock(&xs_state.response_mutex);
mutex_unlock(&xs_state.request_mutex);
/* No need for watches_lock: the suspend_mutex is sufficient. */
void xs_suspend_cancel(void)
{
+ mutex_unlock(&xs_state.response_mutex);
mutex_unlock(&xs_state.request_mutex);
up_write(&xs_state.suspend_mutex);
}
char *body;
int err;
- err = xb_wait_for_data_to_read();
- if (err)
- return err;
-
- msg = kmalloc(sizeof(*msg), GFP_KERNEL);
- if (msg == NULL)
- return -ENOMEM;
-
/*
- * We are now committed to reading an entire message. Partial reads
- * across save/restore leave us out of sync with the xenstore daemon.
+ * We must disallow save/restore while reading a xenstore message.
+ * A partial read across s/r leaves us out of sync with xenstored.
*/
- down_read(&xs_state.suspend_mutex);
+ for (;;) {
+ err = xb_wait_for_data_to_read();
+ if (err)
+ return err;
+ mutex_lock(&xs_state.response_mutex);
+ if (xb_data_to_read())
+ break;
+ /* We raced with save/restore: pending data 'disappeared'. */
+ mutex_unlock(&xs_state.response_mutex);
+ }
+
+
+ msg = kmalloc(sizeof(*msg), GFP_KERNEL);
+ if (msg == NULL) {
+ err = -ENOMEM;
+ goto out;
+ }
err = xb_read(&msg->hdr, sizeof(msg->hdr));
if (err) {
}
out:
- up_read(&xs_state.suspend_mutex);
+ mutex_unlock(&xs_state.response_mutex);
return err;
}
init_waitqueue_head(&xs_state.reply_waitq);
mutex_init(&xs_state.request_mutex);
+ mutex_init(&xs_state.response_mutex);
init_rwsem(&xs_state.suspend_mutex);
/* Initialize the shared memory rings to talk to xenstored */
if not is_hvm and handler.console_mfn is None:
raise XendError('Could not read console MFN')
- dominfo.waitForDevices() # Wait for backends to set up
- if not paused:
- dominfo.unpause()
-
- # get qemu state and create a tmp file for dm restore
+ # get qemu state and create a tmp file for dm restore
if is_hvm:
qemu_signature = read_exact(fd, len(QEMU_SIGNATURE),
"invalid device model signature read")
dominfo.completeRestore(handler.store_mfn, handler.console_mfn)
+ dominfo.waitForDevices() # Wait for backends to set up
+ if not paused:
+ dominfo.unpause()
+
return dominfo
except:
dominfo.destroy()
unsigned int domid;
unsigned long mfn;
evtchn_port_t port;
+ int rc;
if (get_strings(in, vec, ARRAY_SIZE(vec)) < ARRAY_SIZE(vec)) {
send_error(conn, EINVAL);
talloc_steal(domain->conn, domain);
fire_watches(conn, "@introduceDomain", false);
- }
- else {
- int rc;
-
+ } else if (domain->mfn == mfn) {
/* Use XS_INTRODUCE for recreating the xenbus event-channel. */
if (domain->port)
xc_evtchn_unbind(xce_handle, domain->port);
rc = xc_evtchn_bind_interdomain(xce_handle, domid, port);
domain->port = (rc == -1) ? 0 : rc;
domain->remote_port = port;
+ } else {
+ send_error(conn, EINVAL);
+ return;
}
+ /* Rings must be quiesced. */
+ domain->interface->req_cons = domain->interface->req_prod = 0;
+ domain->interface->rsp_cons = domain->interface->rsp_prod = 0;
+
send_ack(conn, XS_INTRODUCE);
}